package com.edgar.plugin.utils;

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.os.Build;
import android.util.Log;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
 * Created by Edgar on 2018/2/10.
 */
public final class NativeLibraryUtils {

    private static final String TAG = "NativeLibraryHelper";

    private NativeLibraryUtils(){}

    private static String getApplicationCpuAbi(Context context){
        ApplicationInfo applicationInfo = context.getApplicationInfo();
        try {
            Field field = applicationInfo.getClass().getField("primaryCpuAbi");
            String cpuAbi = (String) field.get(applicationInfo);
            Log.d(TAG,"Application cpu abi:"+cpuAbi);
            return cpuAbi;
        } catch (NoSuchFieldException e) {
            Log.d(TAG,"No find primaryCpuAbi",e);
        } catch (IllegalAccessException e) {
            Log.e(TAG,"Illegal access",e);
        }
        return null;
    }

    public static void copyNativeLibrary(Context context, File apkFile,File nativeLibraryDir){
        String[] cpuABIs;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            //因为5.0开始,App如果没有so文件,默认是使用64位zygote,所以,这里优先以应用运行的环境为准
            String cpuAbi = getApplicationCpuAbi(context);
            if (cpuAbi == null){
                if (isABI32(Build.SUPPORTED_ABIS[0])){
                    cpuABIs = Build.SUPPORTED_ABIS;
                } else {
                    cpuABIs = new String[]{Build.SUPPORTED_ABIS[0]};
                }
            } else {
                cpuABIs = new String[]{cpuAbi};
            }
        } else {
            cpuABIs = new String[]{Build.CPU_ABI,Build.CPU_ABI2};
        }
        ZipFile zipFile = null;
        try {
            zipFile = new ZipFile(apkFile);
            boolean findCpuAbiSo = false;
            for (String cpuAbi:cpuABIs){
                Log.d(TAG,"Plugin cpu abi:"+cpuAbi);
                Enumeration<? extends ZipEntry> zipEntries = zipFile.entries();
                while (zipEntries.hasMoreElements()){
                    ZipEntry zipEntry = zipEntries.nextElement();
                    final String entryName = zipEntry.getName();
                    if (isSoFile(entryName)){
                        findCpuAbiSo = entryName.startsWith("lib"+File.separator+cpuAbi);
                        if (findCpuAbiSo){
                            String libName = extractSoName(entryName);
                            Log.d(TAG,String.format("Plugin find a match cpu file \"%s\"",entryName));
                            File soFile = new File(nativeLibraryDir,libName);
                            FileUtils.maybeParentMkdirs(soFile);
                            Utils.copy(zipFile.getInputStream(zipEntry),new FileOutputStream(soFile),Utils.BUFFER_SIZE);
                        } else {
                            Log.d(TAG,String.format("Plugin \"%s\" file does not match \"%s\" CPU",entryName,cpuAbi));
                        }
                    }
                }
                if (findCpuAbiSo){
                    return;
                }
            }
        } catch (IOException e) {
            Log.e(TAG,"Read apk failed",e);
        } finally {
            IoUtils.closeZipFile(zipFile);
        }
    }

    private static String extractSoName(String entryName){
        return entryName.substring(entryName.lastIndexOf("/")+1,entryName.length());
    }

    private static boolean isABI32(String cpuAbi){
        cpuAbi = cpuAbi.toLowerCase();
        return cpuAbi.equals("armeabi") || cpuAbi.equals("armeabi-v7a") || cpuAbi.equals("x86");
    }

    private static boolean isSoFile(String filePath){
        return filePath != null && filePath.endsWith(".so");
    }
}